﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using KamLib;

namespace KamLib
{
    public static class UilRouteTable
    {
        #region Зарегистрированные объекты

        /// <summary>
        /// Описанные типы controllers в приложении. Искать по CTID
        /// </summary>
        public static readonly IDictionary<string, UilControllerTypeInfo> ControllerTypes = new SortedDictionary<string, UilControllerTypeInfo>();
        public static readonly IDictionary<Type, UilControllerTypeInfo> ControllerTypesByType = new Dictionary<Type, UilControllerTypeInfo>();

        /// <summary>
        /// Описанные методы handlers в приложении (объявляются как UilMethods в controller adapters). Искать по HID
        /// </summary>
        public static readonly IDictionary<string, IUilMethod> HandlerMethods = new SortedDictionary<string, IUilMethod>();


        /// <summary>
        /// Описанные типы views в приложении. Искать по VTID
        /// </summary>
        public static readonly IDictionary<string, UilViewTypeInfo> ViewTypes = new SortedDictionary<string, UilViewTypeInfo>();

        #endregion

        #region Регистрация всяких UIL-объектов

        /// <summary>
        ///     Регистирует в статические справочники всё, что может (UIL-классы)
        /// </summary>
        /// <param name="type"> </param>
        /// <param name="id"> </param>
        /// <returns> </returns>
        public static bool Register(Type type, string id = null)
        {
            if (typeof(UilController).IsAssignableFrom(type))
            {
                var ci = new UilControllerTypeInfo(type, id);
                ControllerTypes[ci.CTID] = ci;
                ControllerTypesByType[ci.ControllerType] = ci;
                return true;
            }

            if (type.HasAttribute<UilHandlerAttribute>())
            {
                UilRefMethod.GetMethods(type, HandlerMethods, useStatic: true, useFullID: true);
                return true;
            }

            if (type.GetInterface("IUilView") != null)
            {
                var vi = new UilViewTypeInfo(type, id);
                ViewTypes[vi.VTID] = vi;
                return true;
            }

            return false;
        }

        /// <summary>
        ///     Регистирует все указанные UIL-классы
        /// </summary>
        public static void Register(IEnumerable<Type> types)
        {
            foreach (var type in types)
            {
                Register(type);
            }
        }

        /// <summary>
        ///     Регистирует все UIL-классы в assembly
        /// </summary>
        public static void Register(Assembly assembly)
        {
            Register(assembly.GetTypes());
        }

        /// <summary>
        ///     Проверяет готовность зарегистрированных объектов к работе
        /// </summary>
        public static void CheckRegisters()
        {
            //if (ViewNavigators.Count == 0)
            //    throw new Exception("Not registred any UilViewNavigator");
        }

        #endregion


    }

    //public class UilHandlerMethodDictionary : SortedDictionary<string, IUilMethod>
    //{
    //    public IUilMethod Find(string hid) { return ContainsKey(hid) ? this[hid] : null; }
    //    public IUilMethod Get(string hid)
    //    {
    //        var method = Find(hid);
    //        if (method == null)
    //            throw new Exception("Can't find handler method '" + hid + "'.");
    //        return method;
    //    }
    //}


    public class UilControllerTypeInfo
    {
        /// <summary>
        ///     Уникальный в приложении ID типа Controller
        /// </summary>
        public readonly string CTID;
        public readonly Type ControllerType;
        public readonly IEnumerable<UilDescription> Descs;
        public readonly IDictionary<string, IUilMethod> Methods;


        public UilControllerTypeInfo(Type controllerType, string сtid = null)
        {
            if (controllerType == null)
                throw new ArgumentNullException("controllerType");

            ControllerType = controllerType;
            CTID = сtid ?? UilIDAttribute.GetID(controllerType);
            Descs = controllerType.GetAttributes<UilDescription>().ToArray();
            Methods = UilRefMethod.GetMethods(controllerType);
        }

        public UilController NewController(UilContext context, UilKey key)
        {
            var controller = ((UilController)Activator.CreateInstance(ControllerType));
            controller.TypeInfo = this;
            controller.Key = key;
            controller.Initialize(context);
            return controller;
        }
    }


    public class UilViewTypeInfo
    {
        /// <summary>
        ///     Уникальный в приложении ID типа View
        /// </summary>
        public readonly string VTID;

        public readonly Type ViewType;

        public UilViewTypeInfo(Type viewType, string vtid = null)
        {
            if (viewType == null)
                throw new ArgumentNullException("viewType");

            ViewType = viewType;
            VTID = vtid ?? UilIDAttribute.GetID(viewType);
        }

        #region Create View

        public static Func<UilViewTypeInfo, UilContext, UilKey, IUilView> ViewCreater
            = (info, ctx, key) => { throw new NotImplementedException(); };

        public int LastVID { get; private set; }

        /// <summary>
        ///     Генерирует новый VID (ID контрола на странице) для данного типа View
        /// </summary>
        /// <returns> </returns>
        public int NewVID()
        {
            return ++LastVID;
        }

        public IUilView NewView(UilContext context, UilKey key)
        {
            if (ViewCreater == null)
                throw new Exception("The UilViewTypeInfo.ViewCreater is null.");

            if (key != null) key.VID = NewVID();

            return ViewCreater(this, context, key);
        }

        #endregion
    }
}